Skip to content

Fix Sell Max showing entered fiat value in crypto field - #6107

Open
j0ntz wants to merge 1 commit into
developfrom
jon/sell-max-value-switch
Open

Fix Sell Max showing entered fiat value in crypto field#6107
j0ntz wants to merge 1 commit into
developfrom
jon/sell-max-value-switch

Conversation

@j0ntz

@j0ntz j0ntz commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

CHANGELOG

Does this branch warrant an entry to the CHANGELOG?

  • Yes
  • No

Dependencies

none

Requirements

If you have made any visual changes to the GUI. Make sure you have:

  • Tested on iOS device
  • Tested on Android device
  • Tested on small-screen device (iPod Touch)
  • Tested on large-screen device (tablet)

Description

Fixes the Sell scene "Max" bug where the previously entered fiat amount was momentarily copied into the crypto field (e.g. entering 100 USD, then tapping Max, showed 100 in the crypto field before the real max resolved).

Root cause is in handleMaxPress in RampCreateScene.tsx. On the sell path it flipped lastUsedInput to 'crypto' before awaiting the async max calculation, while amountQuery still held the previously entered fiat value { exchangeAmount: '100' }. During that async gap displayCryptoAmount took its lastUsedInput === 'crypto' branch and returned amountQuery.exchangeAmount (the fiat number), so the crypto field rendered the fiat value. On large wallets the max calculation (getMaxSpendable) is slow, so the wrong value lingered and routing stalled.

The fix sets the max amount query before flipping the input type (and no longer flips it before the await), so the display memos take their max branch immediately and the crypto field only ever shows the computed max. Buy is unchanged (its branch has no await, so its state updates already batch).

Hardening around the same async max window (added while addressing review rounds, all folded into the one commit):

  • A manual edit during the compute cancels the in-flight max via a shared cancelPendingMax helper (bumps a monotonic request id, clears the pending auto-nav and the computing spinner), so a late-resolving max cannot overwrite the typed amount or auto-navigate on it.
  • Auto-navigation is suspended while a wallet, fiat, or region picker is open (withPickerOpen / showPickerModal), so a max quote resolving mid-selection cannot navigate out from under the modal; the max keeps computing and navigates once the picker closes.
  • The fiat-change check compares against the resolved displayed fiat, so re-selecting the displayed default no longer cancels an in-flight max.
  • The sell max compute is wrapped in try/catch: on rejection it surfaces the error and recovers instead of leaving the scene blank with auto-nav armed.
  • A spinner + disabled Max shows during the compute (and overlapping Max taps are ignored), so a slow max gives feedback instead of a blank, re-tappable scene.

Asana: https://app.asana.com/0/1215088146871429/1215965639107175

Testing (iOS sim, edge-funds, My Ether 4 / ETH, Sell scene):

  • Entered a fiat amount, tapped Max: the crypto field shows the wallet's max spendable amount, not the fiat value.
  • Hack-verified the transient by temporarily widening the async window: with the fix, during the window the crypto field shows the converted value (not the entered fiat number); reverting to the old ordering under the same widened window reproduces the fiat-in-crypto flash. All temporary edits reverted; working tree clean.

Note

Medium Risk
Changes ramp sell amount state, async max spendable, and auto-navigation timing in RampCreateScene; mistakes could affect quote routing or leave the UI stuck, but scope is limited to the ramp create flow.

Overview
Fixes the Sell scene Max bug where the previously entered fiat amount briefly appeared in the crypto field while max spendable was still computing.

handleMaxPress on sell now clears the amount, defers setting lastUsedInput to 'crypto' until after getMaxSpendExchangeAmount completes, and applies the max query first on buy so display memos use the max branch instead of treating stale fiat as crypto.

Adds cancelPendingMax (monotonic request id), withPickerOpen / showPickerModal so auto-nav after Max does not fire while wallet/fiat/region pickers are open, spinner + disabled Max during compute, error handling via showError, and cancels in-flight max on manual edits, wallet/fiat changes (with correct comparison to displayed fiat), and overlapping Max taps.

Reviewed by Cursor Bugbot for commit 8b35794. Bugbot is set up for automated code reviews on this repo. Configure here.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@j0ntz

j0ntz commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

📸🩹 Test evidence — Sell Max fix (iOS sim)

🩹 Some screenshots below are HACK-FORCED. The marked frames show a state forced by a temporary uncommitted local edit (the natural trigger could not be reproduced on the sim). The hack is not in this PR's diff; the pixels prove the rendering, not the trigger.

sellmax crypto is max not fiat

sellmax crypto is max not fiat

🩹 HACK-FORCED: fixed window crypto not fiat

🩹 HACK-FORCED: fixed window crypto not fiat

🩹 HACK-FORCED: BUGREPRO old ordering fiat in crypto

🩹 HACK-FORCED: BUGREPRO old ordering fiat in crypto

Captured by the agent's in-app test run (build-and-test).

Comment thread src/components/scenes/RampCreateScene.tsx Outdated
@j0ntz
j0ntz force-pushed the jon/sell-max-value-switch branch from b16284c to 26d6272 Compare July 24, 2026 22:17
Comment thread src/components/scenes/RampCreateScene.tsx Outdated
@j0ntz
j0ntz force-pushed the jon/sell-max-value-switch branch from 26d6272 to 3b1202a Compare July 24, 2026 22:24
@j0ntz
j0ntz force-pushed the jon/sell-max-value-switch branch from 3b1202a to 8313d7a Compare July 29, 2026 19:42

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

Claude Code Review is paused for this repository. To reconnect it, an admin of this repository's GitHub organization (or the account owner, for personal repositories) who can also manage your Claude organization's Code Review settings needs to re-link GitHub in Code Review settings. This is a one-time step.

Tip: disable this comment in your organization's Code Review settings.

@j0ntz
j0ntz enabled auto-merge July 29, 2026 19:43
Comment thread src/components/scenes/RampCreateScene.tsx Outdated
Comment thread src/components/scenes/RampCreateScene.tsx Outdated
@j0ntz
j0ntz force-pushed the jon/sell-max-value-switch branch from 8313d7a to fca9989 Compare July 29, 2026 20:09
@j0ntz j0ntz closed this Jul 29, 2026
auto-merge was automatically disabled July 29, 2026 20:53

Pull request was closed

@j0ntz j0ntz reopened this Jul 29, 2026
@j0ntz
j0ntz enabled auto-merge July 29, 2026 20:54
@j0ntz
j0ntz force-pushed the jon/sell-max-value-switch branch from fca9989 to 16292d1 Compare July 29, 2026 20:59
Comment thread src/components/scenes/RampCreateScene.tsx
Comment thread src/components/scenes/RampCreateScene.tsx Outdated
Comment thread src/components/scenes/RampCreateScene.tsx Outdated
Comment thread src/components/scenes/RampCreateScene.tsx Outdated
Comment thread src/components/scenes/RampCreateScene.tsx Outdated
Comment thread src/components/scenes/RampCreateScene.tsx
@j0ntz
j0ntz force-pushed the jon/sell-max-value-switch branch from 2d3b0b7 to 625495a Compare July 29, 2026 23:57

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 625495a. Configure here.

Comment thread src/components/scenes/RampCreateScene.tsx Outdated
Tapping Max on the Sell scene flipped lastUsedInput to 'crypto' before the
async max calculation finished, while amountQuery still held the previously
entered fiat amount. displayCryptoAmount then rendered that fiat value in the
crypto field (e.g. 100 USD shown as 100 BTC) until the max resolved. Set the
max amount query before flipping the input type so the display always shows the
computed max.
@j0ntz
j0ntz force-pushed the jon/sell-max-value-switch branch from 625495a to 8b35794 Compare July 30, 2026 00:11
@j0ntz

j0ntz commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

📸🪓 Test evidence — post-fix re-verification (iOS sim, edge-funds My Ether 4)

🪓 Hack-forced evidence: The two HACKED frames widened the sub-second async max window to make interruption races observable: 07 = a temporary 6s delay in getMaxSpendExchangeAmount; 08 = a temporary throw in the same function. Both hacks were reverted; git status clean before every commit. They prove the interruption handling, not production timing. Temporary uncommitted edit, reverted before commit; the marked frames prove the rendering, not the trigger.

sellmax happy crypto not fiat

sellmax happy crypto not fiat

🪓 HACK-FORCED: f1 type during max not clobbered

🪓 HACK-FORCED: f1 type during max not clobbered

🪓 HACK-FORCED: f3 max error recovers

🪓 HACK-FORCED: f3 max error recovers

Captured by the agent's in-app test run (build-and-test).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants